I am working with a small library which uses DxlObjects to store a tree-like data structure. Basically, each tree node is a DxlObject. One key of each Object is a Skip list with the child nodes. A much simplified version of this approach looks like this:
//
// Create an nested structure of DxlObjects
//
DxlObject createTree(){
DxlObject D_parent = new
DxlObject D_child
Skip S_nodes = create
D_parent -> "text" = "the parent node"
D_child = new
D_child -> "text" = "the first child node"
put (S_nodes, 0, D_child)
D_child = new
D_child -> "text" = "the second child node"
put (S_nodes, 1, D_child)
D_parent -> "nodes" = S_nodes
return D_parent
}
//
// print the nested DxlObjects
//
void printTree ( DxlObject D_tree ){
DxlObject D_child
print ( string D_tree -> "text" )
for D_child in ( Skip D_tree -> "nodes" ) do {print "\n\t" ( string D_child -> "text" )}
}
//
// clean everything up
//
void cleanTree ( DxlObject D_tree ){
Skip S = ( Skip D_tree -> "nodes" )
DxlObject D_child
if ( ! null S){ for D_child in S do {cleanTree(D_child)}}
delete D_tree
delete S
}
//
// Example
//
DxlObject D_tree = createTree()
printTree(D_tree)
//
// Clean up
//
cleanTree(D_tree)
So far, so good. Today, however, I tried to define a for loop such that I could hide the internal ( Skip D_tree -> "nodes" ) from the code working with the tree data. With other words, I'd like to do
DxlObject D_child
for D_child in D_tree do {
print "\n\t" ( string D_child -> "text" )
}
My only problem is that I can't get my head around the proper coding of the necessary void ::do routine:
void ::do ( DxlObject &D_loop, DxlObject D_parent, void doit ){
Skip S = ( Skip D_parent -> "nodes" )
DxlObject D
for D in S do {
// ???
}
}
I am lost here, and I would appreciate any working example of such a customized for loop for inspiration. Cheers, Peter Peter_Albert - Thu Jan 05 12:09:32 EST 2017 |
Re: User-defined for loop Cannot do. If you look at the ternary ::do operator, you can see that it has three parameters. The third parameter is actually the loop body, something you cannot create in DXL. Additionally DXL will not handle the syntax correctly, so doing "for a in b" will never call your operator. Alternatives: 1. Use a Skip return (not the same I know)
Skip items(DxlObject dx) {
Skip sk = create();
...
return sk;
}
...
Skip sk = items myTree
for item in sk do ...
delete sk
2. Make your own iterator and use a while loop
item = null;
while (iterate(myTree, item)) {
...
}
bool iterate(DxlObject dx, int &item) {
... fetch items and return stuff ...
}
Note: You need to reset your iterator position when returning false
Another note: You should not use DxlObject, but rather a custom struct.
struct MyTree {};
DxlObject DxlObjectOf(MyTree t) { return (addr_ t) DxlObject; }
MyTree MyTreeOf(DxlObject dx) { return (addr_ dx) MyTree; }
MyTree getParent(MyTree t) { return ((DxlObjectOf t)->"Parent") MyTree; }
void setParent(MyTree t, MyTree parent) { (DxlObjectOf t)->"Parent" = parent; }
MyTree createMyTree () {
DxlObject dx = new();
return MyTreeOf dx;
}
Hope that helps, regards, Mathias
|
Re: User-defined for loop Mathias Mamsch - Fri Jan 06 15:03:21 EST 2017 Cannot do. If you look at the ternary ::do operator, you can see that it has three parameters. The third parameter is actually the loop body, something you cannot create in DXL. Additionally DXL will not handle the syntax correctly, so doing "for a in b" will never call your operator. Alternatives: 1. Use a Skip return (not the same I know)
Skip items(DxlObject dx) {
Skip sk = create();
...
return sk;
}
...
Skip sk = items myTree
for item in sk do ...
delete sk
2. Make your own iterator and use a while loop
item = null;
while (iterate(myTree, item)) {
...
}
bool iterate(DxlObject dx, int &item) {
... fetch items and return stuff ...
}
Note: You need to reset your iterator position when returning false
Another note: You should not use DxlObject, but rather a custom struct.
struct MyTree {};
DxlObject DxlObjectOf(MyTree t) { return (addr_ t) DxlObject; }
MyTree MyTreeOf(DxlObject dx) { return (addr_ dx) MyTree; }
MyTree getParent(MyTree t) { return ((DxlObjectOf t)->"Parent") MyTree; }
void setParent(MyTree t, MyTree parent) { (DxlObjectOf t)->"Parent" = parent; }
MyTree createMyTree () {
DxlObject dx = new();
return MyTreeOf dx;
}
Hope that helps, regards, Mathias
Hi Mathias, many thanks for your response. In the end, I went for a modified version of your first Alternative, which is almost where I wanted to land:
Skip ::[] ( DxlObject D, string s){return ( Skip D -> s )}
DxlObject D_tree = createTree()
DxlObject D_node
for D_node in D_tree["nodes"] do {}
cleanTree(D_tree)
P.S.: Would you mind explaining why DxlObjects should not be used?
Best regards, Peter |
Re: User-defined for loop Peter_Albert - Mon Jan 09 02:11:06 EST 2017 Hi Mathias, many thanks for your response. In the end, I went for a modified version of your first Alternative, which is almost where I wanted to land:
Skip ::[] ( DxlObject D, string s){return ( Skip D -> s )}
DxlObject D_tree = createTree()
DxlObject D_node
for D_node in D_tree["nodes"] do {}
cleanTree(D_tree)
P.S.: Would you mind explaining why DxlObjects should not be used?
Best regards, Peter Regarding the P.S: 1. When you make a nice tree, you might want to put it in a library. When you put it in a library, you soon will make another library ... Maybe a list. And when you make a list, you might want to make another function Skip ::[] (DxlObject, ...)... And at some point you will get into namespacing problems.
2. With the struct variant declaring "getters" and "setters" you will hide the implementation of your underlying DXLObject. When you use this tree on large data you will probably decide to make each treeNode one row inside a large array, instead of allocation one DXL Object for each node. With the DxlObject hidden you can easily make this change without impacting other code.
3. With getters and setters for your properties you will benefit from autocompletion inside good editors. Also you can hide other specifics inside your objects. For example if you decide for performance reasons, that your tree will not only store the first child, but also the last child for easier append. Since the outer code does not know about the inner workings of your data, you can make all those kinds of changes without affecting the code that uses your object. Find attached an example Tree implementation in DXL called "Hierarchy" (feel free to rename to tree). Maybe that helps, regards, Mathias Attachments Hierarchy.inc |
Re: User-defined for loop Mathias Mamsch - Mon Jan 09 04:27:26 EST 2017 Regarding the P.S: 1. When you make a nice tree, you might want to put it in a library. When you put it in a library, you soon will make another library ... Maybe a list. And when you make a list, you might want to make another function Skip ::[] (DxlObject, ...)... And at some point you will get into namespacing problems.
2. With the struct variant declaring "getters" and "setters" you will hide the implementation of your underlying DXLObject. When you use this tree on large data you will probably decide to make each treeNode one row inside a large array, instead of allocation one DXL Object for each node. With the DxlObject hidden you can easily make this change without impacting other code.
3. With getters and setters for your properties you will benefit from autocompletion inside good editors. Also you can hide other specifics inside your objects. For example if you decide for performance reasons, that your tree will not only store the first child, but also the last child for easier append. Since the outer code does not know about the inner workings of your data, you can make all those kinds of changes without affecting the code that uses your object. Find attached an example Tree implementation in DXL called "Hierarchy" (feel free to rename to tree). Maybe that helps, regards, Mathias Many thanks for your quick reply and the include file ... very helpful! |